package com.chenfan.process.config.job;

import com.alibaba.fastjson.JSONObject;
import com.chenfan.infra.context.TenantContextHolder;
import com.chenfan.infra.utils.StringUtils;
import com.chenfan.notify.MessageClient;
import com.chenfan.process.entity.po.ApprovalPo;
import com.chenfan.process.entity.po.ApprovalTemplatePo;
import com.chenfan.process.entity.po.ProcessInstanceApprovePo;
import com.chenfan.process.entity.po.TemplateConfigPo;
import com.chenfan.process.enums.ApprovalMessageTypeEnum;
import com.chenfan.process.service.ApprovalService;
import com.chenfan.process.service.ApprovalTemplateService;
import com.chenfan.process.service.ProcessInstanceApproveService;
import com.chenfan.process.service.TemplateConfigService;
import com.chenfan.process.util.MessageCenterHelper;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
@RefreshScope
public class OverDueMessageRemindXXlJob {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ApprovalService approvalService;
    @Autowired
    private ProcessInstanceApproveService processInstanceApproveService;
    @Autowired
    private ApprovalTemplateService approvalTemplateService;
    @Autowired
    private TemplateConfigService templateConfigService;
    @Autowired
    private MessageClient messageClient;
    @Value("${overDueDay:7}")
    private Integer overDueDay;

    public static final String OVERDUE_MESSAGE = "messageRemind:overdueMessage";
    public static final int DAY = 86400;

    @XxlJob("overDueMessage")
    public ReturnT<String> overDueMessage(String param) {
        log.info("扫描超期提醒定时任务开始执行...");
        Set<Long> approvalIdSet = redisTemplate.opsForZSet().rangeByScore(OVERDUE_MESSAGE, 0, System.currentTimeMillis(), 0, 10);
        log.info("扫描超期提醒数据:{}", JSONObject.toJSONString(approvalIdSet));
        // 增加模板Cache
        Map<Long, ApprovalTemplatePo> templateCache = new HashMap<>();
        Map<String, TemplateConfigPo> configCache = new HashMap<>();
        TenantContextHolder.setTenantId(1L);
        for(Long approvalId: approvalIdSet) {
            ApprovalPo approval = approvalService.findApprovalByApprovalIdWithoutTenantId(approvalId);
            if (Objects.isNull(approval) || approval.isFinish()) {
                // 如果审批流已经完毕, 直接移除
                redisTemplate.opsForZSet().remove(OVERDUE_MESSAGE, approvalId);
                continue;
            }
            ApprovalTemplatePo templatePo = templateCache.get(approval.getApprovalTemplateId());
            if (Objects.isNull(templatePo)) {
                templatePo = approvalTemplateService.getById(approval.getApprovalTemplateId());
                templateCache.put(templatePo.getId(), templatePo);
            }
            String configKey = StringUtils.joinWith("_", templatePo.getId(), templatePo.getVersion());
            TemplateConfigPo config = configCache.get(configKey);
            if (Objects.isNull(config)) {
                config = templateConfigService.getByTemplateId(approval.getApprovalTemplateId(), approval.getVersion());
                configCache.put(configKey, config);
            }

            // 查询对应的数据
            List<ProcessInstanceApprovePo> processInstanceApprovePoList = processInstanceApproveService.listApprovingInstances(Collections.singletonList(approvalId));

            //发送默认消息模板-审批通知
            MessageCenterHelper.sendDefault(ApprovalMessageTypeEnum.APPROVAL_OVERDUE, templatePo, approval,
                    processInstanceApprovePoList.stream().map(ProcessInstanceApprovePo::getUserId).collect(Collectors.toList()),
                    config, null);

            // 继续放入队列中
            redisTemplate.opsForZSet().add(OverDueMessageRemindXXlJob.OVERDUE_MESSAGE, approvalId, System.currentTimeMillis() + overDueDay * OverDueMessageRemindXXlJob.DAY);
        }
        return ReturnT.SUCCESS;
    }
}